package com.plm.k8s.myk8sapi.cmd.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.plm.k8s.myk8sapi.cmd.AbstractLocalCmd;
import com.plm.k8s.myk8sapi.cmd.IDeploymentCmd;
import com.plm.k8s.myk8sapi.pojo.entity.deployment.*;
import com.plm.k8s.myk8sapi.pojo.entity.pod.*;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.*;

@Service
public class DeploymentCmdImpl extends AbstractLocalCmd implements IDeploymentCmd {

    @Override
    public List<DeploymentEntity> listDeployments(boolean isAll, String namespace, String nameFilter,
            Map<String, String> labelFilter) throws Exception {
        String cmd = generateListDeploymentsCmd(isAll, namespace, nameFilter, labelFilter);
        ApiDeploymentEntity employment = execForYamlObject(cmd, ApiDeploymentEntity.class);
        if (employment == null) return Collections.emptyList();
        return employment.getItems();
    }

    @Override
    public boolean createDeployment(File yamlFile) throws Exception {
        String result = applyYamlFile(yamlFile);
        if (!result.contains("created")) {
            throw new Exception(result);
        }
        return true;
    }

    @Override
    public boolean createDeployment(String name, String image, Integer replicas, String imagePullPolicy,
            List<PodSpecContainerEnvEntity> envs, List<PodSpecContainerPortEntity> ports,
            List<PodSpecContainerVolumeMountEntity> volumeMounts, List<PodSpecVolumeEntity> volumes, String namespace,
            Integer terminationGracePeriodSeconds, List<String> command, PodSpecContainerStartupProbeEntity startupProbe,
            PodSpecContainerLivenessProbeEntity livenessProbe, PodSpecContainerReadinessProbeEntity readinessProbe,
            PodSpecContainerLifecycleEntity lifecycle, PodSpecContainerResourcesRequestsEntity requests,
            PodSpecContainerResourcesLimitsEntity limits) throws Exception {
        if (!StringUtils.hasText(name)) throw new Exception("控制器名称不能为空");
        if (!StringUtils.hasText(image)) throw new Exception("镜像名称不能为空");
        DeploymentEntity deploymentEntity = generateBaseDeployment(name, replicas);
        setMoreDeploymentInfo(deploymentEntity, name, image, imagePullPolicy, envs, ports, volumeMounts, volumes, namespace,
                terminationGracePeriodSeconds, command, startupProbe, livenessProbe, readinessProbe, lifecycle, requests,
                limits);
        File file = transferObject2YamlFile(deploymentEntity);
        return createDeployment(file);
    }

    @Override
    public boolean deleteDeployment(String name, String namespace, boolean force) throws Exception {
        if (!StringUtils.hasText(name)) throw new Exception("deployment控制器名称不能为空");
        String cmd = generateDeleteDeploymentCmd(name, namespace, force);
        String result = exec(cmd);
        if (!String.format("deployment.apps \"%s\" deleted", name).equals(trimBr(result))) {
            throw new Exception(result);
        }
        return true;
    }

    @Override
    public boolean scaleDeployment(String name, Integer replicas, String namespace) throws Exception {
        if (!StringUtils.hasText(name)) throw new Exception("控制器名称不能为空");
        if (replicas == null) throw new Exception("控制器副本数不能为空");
        String cmd = generateScaleDeploymentCmd(name, replicas, namespace);
        String result = exec(cmd);
        if (!String.format("deployment.apps/%s scaled", name).equals(trimBr(result))) {
            return false;
        }
        return true;
    }

    private String generateScaleDeploymentCmd(String name, Integer replicas, String namespace) {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("scale deployment ").append(name).append(" --replicas=").append(replicas);
        if (StringUtils.hasText(namespace)) addNamespace(sb, namespace);
        return sb.toString();
    }

    private String generateDeleteDeploymentCmd(String name, String namespace, boolean force) {
        StringBuilder sb = new StringBuilder();
        sb.append(generateKubeCmdBase()).append("delete deployments").append(CMD_DELIMITER).append(name);
        if (StringUtils.hasText(namespace)) addNamespace(sb, namespace);
        sb.append(CMD_DELIMITER).append("--force=").append(force);
        return sb.toString();
    }

    /**
     * 设置更多关于deployment的信息
     * @param deploymentEntity
     * @param name
     * @param image
     * @param envs
     * @param ports
     * @param volumeMounts
     * @param volumes
     * @param namespace
     * @param terminationGracePeriodSeconds
     * @param command
     * @param startupProbe
     * @param livenessProbe
     * @param readinessProbe
     * @param lifecycle
     */
    private void setMoreDeploymentInfo(DeploymentEntity deploymentEntity, String name, String image, String imagePullPolicy,
            List<PodSpecContainerEnvEntity> envs, List<PodSpecContainerPortEntity> ports,
            List<PodSpecContainerVolumeMountEntity> volumeMounts, List<PodSpecVolumeEntity> volumes, String namespace,
            Integer terminationGracePeriodSeconds, List<String> command, PodSpecContainerStartupProbeEntity startupProbe,
            PodSpecContainerLivenessProbeEntity livenessProbe, PodSpecContainerReadinessProbeEntity readinessProbe,
            PodSpecContainerLifecycleEntity lifecycle, PodSpecContainerResourcesRequestsEntity requests, PodSpecContainerResourcesLimitsEntity limits) {
        if (StringUtils.hasText(namespace)) deploymentEntity.getMetadata().setNamespace(namespace);
        DeploymentSpecTemplateSpecEntity templateSpecEntity = deploymentEntity.getSpec().getTemplate().getSpec();
        if (CollectionUtil.isNotEmpty(volumes)) templateSpecEntity.setVolumes(volumes);
        if (terminationGracePeriodSeconds != null) templateSpecEntity.setTerminationGracePeriodSeconds(terminationGracePeriodSeconds);
        PodSpecContainerEntity containerEntity = new PodSpecContainerEntity();
        containerEntity.setImage(image);
        containerEntity.setName(name);
        if (StringUtils.hasText(imagePullPolicy)) containerEntity.setImagePullPolicy(imagePullPolicy);
        if (CollectionUtil.isNotEmpty(envs)) containerEntity.setEnv(envs);
        if (CollectionUtil.isNotEmpty(ports)) containerEntity.setPorts(ports);
        if (CollectionUtil.isNotEmpty(volumeMounts)) containerEntity.setVolumeMounts(volumeMounts);
        if (CollectionUtil.isNotEmpty(command)) containerEntity.setCommand(command);
        if (startupProbe != null) containerEntity.setStartupProbe(startupProbe);
        if (livenessProbe != null) containerEntity.setLivenessProbe(livenessProbe);
        if (readinessProbe != null) containerEntity.setReadinessProbe(readinessProbe);
        if (lifecycle != null) containerEntity.setLifecycle(lifecycle);
        PodSpecContainerResourcesEntity resourcesEntity = new PodSpecContainerResourcesEntity();
        if (requests != null) resourcesEntity.setRequests(requests);
        if (limits != null) resourcesEntity.setLimits(limits);
        containerEntity.setResources(resourcesEntity);
        templateSpecEntity.getContainers().add(containerEntity);
    }

    /**
     * 生成基础的deployment信息
     * @param name
     * @param replicas
     * @return
     */
    private DeploymentEntity generateBaseDeployment(String name, Integer replicas) {
        DeploymentEntity deploymentEntity = new DeploymentEntity();
        deploymentEntity.setApiVersion("apps/v1");
        deploymentEntity.setKind("Deployment");
        /******************生成元数据信息********************/
        DeploymentMetadataEntity metadataEntity = new DeploymentMetadataEntity();
        Map<String, String> labelsMap = new LinkedHashMap<>();
        labelsMap.put("app", name);
        metadataEntity.setLabels(labelsMap);
        metadataEntity.setName(name);
        deploymentEntity.setMetadata(metadataEntity);

        /******************生成规格信息********************/
        DeploymentSpecEntity specEntity = new DeploymentSpecEntity();
        if (replicas == null) replicas = 1;
        specEntity.setReplicas(replicas);
        DeploymentSpecSelectorEntity selectorEntity = new DeploymentSpecSelectorEntity();
        Map<String, String> matchLabels = new LinkedHashMap<>();
        matchLabels.put("app", name);
        selectorEntity.setMatchLabels(matchLabels);
        specEntity.setSelector(selectorEntity);
        specEntity.setStrategy(new DeploymentSpecStrategyEntity());
        DeploymentSpecTemplateEntity templateEntity = new DeploymentSpecTemplateEntity();
        DeploymentSpecTemplateMetadataEntity templateMetadata = new DeploymentSpecTemplateMetadataEntity();
        Map<String, String> templateLabels = new LinkedHashMap<>();
        templateLabels.put("app", name);
        templateMetadata.setLabels(templateLabels);
        templateEntity.setMetadata(templateMetadata);
        DeploymentSpecTemplateSpecEntity templateSpecEntity = new DeploymentSpecTemplateSpecEntity();
        templateSpecEntity.setContainers(new LinkedList<>());
        templateEntity.setSpec(templateSpecEntity);
        specEntity.setTemplate(templateEntity);
        deploymentEntity.setSpec(specEntity);

        /******************生成状态信息********************/
        DeploymentStatusEntity deploymentStatusEntity = new DeploymentStatusEntity();
        deploymentEntity.setStatus(deploymentStatusEntity);
        return deploymentEntity;
    }

    private String generateListDeploymentsCmd(boolean isAll, String namespace, String nameFilter,
            Map<String, String> labelFilter) {
        StringBuilder sb = new StringBuilder();
        sb.append(generateKubeCmdBase()).append("get deployments -o yaml");
        if (isAll) {
            sb.append(" -A");
        } else {
            if (StringUtils.hasText(namespace)) addNamespace(sb, namespace);
        }
        if (StringUtils.hasText(nameFilter)) addNameFilter(sb, nameFilter);
        if (CollectionUtil.isNotEmpty(labelFilter)) addLabelFilter(sb, labelFilter);
        return sb.toString();
    }
}
